﻿#ifndef LK_RANDOM_/**@author 由W意波(LuoJun)编写*/
#define LK_RANDOM_
namespace LK
{
	/**
	@brief 表示一个随机数生成器*/
	struct Random :virtual Object, virtual ICloneables
	{
	public:
		/**
		@brief 状态量数据*/
		PObject arr;
		//基类通用方法
		BMETHODS(PRandom, Random)
		/**
		@brief 复制构造*/
		Random(Random const &vr);
		//交换
		void SwapWith(Random& x);
		//赋值
		Random& operator= (const Random& v);
		/**
		@brief 默认构造，每次构造的序列都有可能不一样*/
		Random();
		/**
		@brief 获取状态数组引用*/
		inline Collection::PArray<u64>& GetArray()const { return (Collection::PArray<u64>&)arr; }
		/**
		@brief 使用一个种子进行初始化，相当于调用SetNextRand()
		@param [传入]参数seed表示指定的种子
		@param [传入，可选]参数len表示指定的状态增量数，默认是1*/
		Random(unsigned long long seed, size_t len = 1);
		/**
		@brief 使用一个状态量数组进行初始化*/
		Random(const Collection::PArray<u64> arr);
		/**
		@brief 返回一个浅表副本*/
		Random* Clone()const { return new Random(*this); }
		/**
		@brief 设置下一个值，这样得到的序列将是不固定的
		@param [传入]参数next表示下一个随机值*/
		virtual void SetNextRand(unsigned long long next);
		/**
		@brief 按标准形式设置下一个值，这样得到的序列将是固定的
		@param [传入]参数next表示下一个随机值
		@note 使用SecretRand会破坏序列的固定性*/
		virtual void SetNextRandStatic(unsigned long long next);
		/**
		@brief 获取一个unsigned long long型随机值*/
		virtual unsigned long long Rand();
		/**
		@brief 获取一个unsigned long long型随机数组*/
		virtual void Rand(u64* p, size_t len) { while (len-- != 0)*p++ = Rand(); }
		/**
		@brief 获取一个unsigned long long型随机值
		@note 默认情况下该函数将随机数跟当前的时间进行异或*/
		virtual unsigned long long SecretRand();
		/**
		@brief 获取一个unsigned long long型随机数组*/
		virtual void SecretRand(u64* p, size_t len) { while (len-- != 0)*p++ = SecretRand(); }
		/**
		@brief 获取一个[0,MaxValues::LongLong]的随机数*/
		signed long long NextInt64() { return Rand()&MaxValues::LongLong; }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed long long NextInt64(long long minValue, long long maxValue) { return Rand() % (unsigned long long)(maxValue - minValue + 1) + minValue; }
		/**
		@brief 获取一个[0,MaxValues::UnsignedLongLong]的随机数*/
		unsigned long long NextUInt64() { return Rand(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned long long NextUInt64(long long minValue, long long maxValue) { return Rand() % (unsigned long long)(maxValue - minValue + 1) + minValue; }
		/**
		@brief 获取一个[0,1)的随机小数*/
		double NextDouble();
		/**
		@brief 获取一个[minValue,maxValue)的随机小数*/
		double NextDouble(double minValue, double maxValue) { return (maxValue - minValue)*NextDouble() + minValue; }
		/**
		@brief 获取一个[0,2147483647]的随机数*/
		signed int NextInt();
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed int NextInt(int minValue, int maxValue) { return (int)NextInt64(minValue, maxValue); }
		/**
		@brief 获取一个[0,32767]的随机数*/
		signed short NextShort();
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed short NextShort(short minValue, short maxValue) { return (short)NextInt64(minValue, maxValue); }
		/**
		@brief 获取一个[0,127]的随机数*/
		signed char NextChar();
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed char NextChar(signed char minValue, signed char maxValue) { return (char)NextInt64(minValue, maxValue); }
		/**
		@brief 获取一个无符号Int型随机数*/
		unsigned int NextUInt();
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned int NextUInt(unsigned int minValue, unsigned int maxValue) { return (unsigned int)NextUInt64(minValue, maxValue); }
		unsigned short NextUShort();
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned short NextUShort(unsigned short minValue, unsigned short maxValue) { return (unsigned short)NextUInt64(minValue, maxValue); }
		unsigned char NextUChar();
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned char NextUChar(unsigned char minValue, unsigned char maxValue) { return (unsigned char)NextUInt64(minValue, maxValue); }
		/**
		@brief unsigned long long自动转换*/
		operator unsigned long long()const;
#ifdef _CLR /**@brief 托管支持*/
		/**@brief 从托管随机数初始化*/
		Random& operator=(System::Random^);
#endif
	};
	/**@brief 表示一个随机数生成器的引用*/
	struct PRandom :PObject
	{
	public:
		/*基类通用方法*/
		PIMETHODS_NODEFCTOR(PRandom, Random);
		/**
		@brief 引用默认的随机生成器*/
		PRandom() :PObject(GetDefaultRef()) {}
		/**
		@brief 设置下一个值，这样得到的序列将是不固定的
		@param [传入]参数seed表示下一个随机值*/
		void SetNextRand(unsigned long long seed) { Ptr()->SetNextRand(seed); }
		/**
		@brief 按标准形式设置下一个值，这样得到的序列将是固定的*/
		void SetNextRandStatic(unsigned long long seed) { Ptr()->SetNextRandStatic(seed); }
		/**
		@brief 按标准形式设置下一个值，这样得到的序列将是固定的
		@param [传入]参数seed表示下一个随机值
		@param[传入，可选]参数len表示指定的状态增量数，默认是1
		@note 使用SecretRand会破坏序列的固定性*/
		PRandom(unsigned long long seed, size_t len = 1) :PObject(new Random(seed, len)) {}
		/**
		@brief 获取一个unsigned long long型随机值*/
		unsigned long long Rand() { return Ptr()->Rand(); }
		/**
		@brief 获取一个unsigned long long型随机值
		@note 该函数将每隔一段时间就通过获取的时间来进行微量调整*/
		unsigned long long SecretRand() { return Ptr()->SecretRand(); }
		/**
		@brief 获取一个[0,MaxValues::LongLong]的随机数*/
		signed long long NextInt64() { return Rand()&MaxValues::LongLong; }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed long long NextInt64(long long minValue, long long maxValue) { return Rand() % (unsigned long long)(maxValue - minValue + 1) + minValue; }
		/**
		@brief 获取一个[0,MaxValues::UnsignedLongLong]的随机数*/
		unsigned long long NextUInt64() { return Rand(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned long long NextUInt64(long long minValue, long long maxValue) { return Rand() % (unsigned long long)(maxValue - minValue + 1) + minValue; }
		/**
		@brief 获取一个[0,1)的随机小数*/
		double NextDouble() { return Ptr()->NextDouble(); }
		/**
		@brief 获取一个[minValue,maxValue)的随机小数*/
		double NextDouble(double minValue, double maxValue) { return (maxValue - minValue)*NextDouble() + minValue; }
		/**
		@brief 获取一个[0,2147483647]的随机数*/
		signed int NextInt() { return Ptr()->NextInt(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed int NextInt(int minValue, int maxValue) { return (int)NextInt64(minValue, maxValue); }
		/**
		@brief 获取一个[0,32767]的随机数*/
		signed short NextShort() { return Ptr()->NextShort(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed short NextShort(short minValue, short maxValue) { return (short)NextInt64(minValue, maxValue); }
		/**
		@brief 获取一个[0,127]的随机数*/
		signed char NextChar() { return Ptr()->NextChar(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		signed char NextChar(char minValue, char maxValue) { return (char)NextInt64(minValue, maxValue); }
		/**
		@brief 获取一个无符号Int型随机数*/
		unsigned int NextUInt() { return Ptr()->NextUInt(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned int NextUInt(unsigned int minValue, unsigned int maxValue) { return (unsigned int)NextUInt64(minValue, maxValue); }
		unsigned short NextUShort() { return Ptr()->NextUShort(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned short NextUShort(unsigned short minValue, unsigned short maxValue) { return (unsigned short)NextUInt64(minValue, maxValue); }
		unsigned char NextUChar() { return Ptr()->NextUChar(); }
		/**
		@brief 获取一个[minValue,maxValue]的随机数*/
		unsigned char NextUChar(unsigned char minValue, unsigned char maxValue) { return (unsigned char)NextUInt64(minValue, maxValue); }
		/**
		@brief long long自动转换*/
		operator unsigned long long()const { return *Ptr(); }
		/**
		@brief 默认的随机算子，使用64位的梅森旋转法*/
		static PRandom& GetDefaultRef();
#ifdef _CLR /**@brief 托管支持*/
		/**
		@brief 从托管随机数初始化*/
		PRandom& operator=(System::Random^r) { *Ptr() = r; return *this; }
#endif
	};

	struct PMt64Random;
	/**
	@brief 表示一个64位梅森旋转随机数生成器
	@note 基于 Makoto Matsumoto 和 Takuji Nishimura (c) 2004 的C实现：http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c*/
	struct Mt64Random : Random
	{
	public:
		//基类通用方法
		BMETHODS(PMt64Random, Mt64Random)
			/**
			@brief 默认构造函数，构造一个梅森旋转随机数*/
			Mt64Random();
		/**
		@brief 构造函数，使用一个seed来初始化随机数状态*/
		Mt64Random(u64 seed);
		/**
		@brief 设置下一个值，这样得到的序列将是不固定的
		@param [传入]参数seed表示下一个随机值*/
		virtual void SetNextRand(u64 seed);
		/**
		@brief 按标准形式设置下一个值，这样得到的序列将是固定的
		@param [传入]参数seed表示下一个随机值
		@note 使用SecretRand会破坏序列的固定性*/
		virtual void SetNextRandStatic(u64 seed);
		/**
		@brief 使随机数进入下一个状态*/
		void Generate();
		/**
		@brief 获取一个unsigned long long型随机值*/
		virtual u64 Rand();

	};

	struct PMt64Random :PRandom
	{
		PMETHODS(PMt64Random, Mt64Random)
	};
}
#endif
